package file

import (
	"fmt"
	"os"
	"path"
	"strings"
	"time"

	"gitee.com/shuwenhe/shuwen/log/mylog/util"
)

type Level uint16 // 日志级别

const ( // 5种日志级别
	Debug Level = iota // 开模式调试，线上生产环境不用
	Info               // 给用户看
	Warn               // 系统可以恢复到正常状态
	Error              // 错误可能无法修复会宕机
	Fatal              // 无法修复保留有效数据并停机
)

// 根据传进来的level获取对应的字符串
func getLevel(level Level) string {
	switch level {
	case Debug:
		return "DEBUG"
	case Info:
		return "INFO"
	case Warn:
		return "WARN"
	case Error:
		return "ERROR"
	case Fatal:
		return "FATAL"
	default:
		return "DEBUG"
	}
}

// 根据用户传入的字符串类型的日志级别，解析出对应的Level
func ParseLogLevel(level string) Level {
	level = strings.ToLower(level)
	switch level {
	case "debug":
		return Debug
	case "info":
		return Info
	case "warn":
		return Warn
	case "error":
		return Error
	case "fatal":
		return Fatal
	default:
		return Debug
	}
}

type FileLogger struct { // 文件日志结构体
	level    Level // 日志级别
	FileName string
	FilePath string
	File     *os.File
	ErrFile  *os.File
}

func NewFileLogger(level, FileName, FilePath string) *FileLogger { // 文件日志结构体构造函数
	logLevel := ParseLogLevel(level)
	f1 := &FileLogger{
		level:    logLevel,
		FileName: FileName,
		FilePath: FilePath,
	}
	f1.InitFile() // 根据上面的文件路径和文件名open log file ,把文件句柄赋值给结构体对应的字段
	return f1
}

func (f *FileLogger) InitFile() { // 将指定的日志文件打开 赋值给结构体
	logName := path.Join(f.FilePath, f.FileName)
	file, err := os.OpenFile(logName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0664) // 打开文件
	if err != nil {
		panic(fmt.Errorf("Open log file %s fail,%v", logName, err))
	}
	f.File = file
	errLogName := fmt.Sprintf("%s.err", logName) // Open the error log file
	errFile, err := os.OpenFile(errLogName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0664)
	if err != nil {
		panic(fmt.Errorf("Open log file %s fail,%v", errLogName, err))
	}
	f.ErrFile = errFile
}

func (f *FileLogger) log(level Level, format string, args ...interface{}) {
	if f.level > Debug {
		return
	}
	msg := fmt.Sprintf(format, args...)                    // 得到用户要记录的日志
	nowStr := time.Now().Format("2006-01-02 15:04:05.000") // log格式:[time][file:line num][func name][log level]log message
	fileName, line, funcName := util.GetCallerInfo(3)
	logLevel := getLevel(level)
	logMsg := fmt.Sprintf("[%s][%s:%d][%s]%s", nowStr, fileName, line, funcName, logLevel, msg)
	fmt.Fprintln(f.File, logMsg) // 利用fmt包将msg字符串写入f.file文件中
	if level >= Error {          // 如果是error或者fatal级别的日志还要记录到f.errFile
		fmt.Fprintln(f.ErrFile, logMsg)
	}
}

func (f *FileLogger) Debug(format string, args ...interface{}) { // Debug Level = iota 开发者调试
	f.log(Debug, format, args...)
}

// Info 给用户看
func (f *FileLogger) Info(format string, args ...interface{}) { // Debug Level = iota 开发者调试
	f.log(Debug, format, args...)
}

// Warn 系统可以恢复到正常状态
func (f *FileLogger) Warn(format string, args ...interface{}) { // Debug Level = iota 开发者调试
	f.log(Debug, format, args...)
}

// Error 错误可能无法修复会=>宕机
func (f *FileLogger) Error(format string, args ...interface{}) { // Debug Level = iota 开发者调试
	f.log(Debug, format, args...)
}

// Fatal 无法修复=>保留有效数据并停机
func (f *FileLogger) Fatal(format string, args ...interface{}) { // Debug Level = iota 开发者调试
	f.log(Debug, format, args...)
}
